﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

using BuzzwordBingo.Interface.API;

namespace BuzzwordBingo.ConsoleClient
{
    /// <summary>
    /// A keystroke driven menu.
    /// </summary>
    class ConsoleMenu
    {
        #region private members

        private SetupBingoEventClient _setupClient = new SetupBingoEventClient();
        private PlayBingoEventClient _playClient = new PlayBingoEventClient();
        private int _menuState = (int)MenuState.MAIN;
        private BuzzwordCategoryDto[] _categories = null;
        private string _eventId = "1";
        private BingoEventDto _event = null;
        private ParticipantDto _winner = null;
        private ParticipantDto _playerParticipant = null;

        #endregion

        #region public methods

        /// <summary>
        /// Main loop that processes input commands.
        /// </summary>
        public void Run()
        {
            try
            {
                ConsoleKeyInfo key;
                string inputString = string.Empty;

                Console.WriteLine("BuzzwordBingo.ConsoleClient");
                Console.WriteLine("---------------------------");
                ShowMenu();

                while (true)
                {
                    key = Console.ReadKey();
                    if (key.Key == ConsoleKey.C && key.Modifiers == ConsoleModifiers.Control)
                        break;
                    if (key.Key == ConsoleKey.Backspace)
                        inputString = inputString.Substring(0, inputString.Length - 1);
                    else
                        inputString += key.KeyChar;
                    if (key.Key == ConsoleKey.Enter)
                    {
                        ProcessCommand(inputString.Trim());
                        inputString = string.Empty;
                    }
                }
                _setupClient.Close();
                _playClient.Close();
            }
            catch (TimeoutException e)
            {
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(e);
                _setupClient.Abort();
                _playClient.Abort();
            }
            catch (CommunicationException e)
            {
                Console.ForegroundColor = ConsoleColor.Yellow;
                Console.WriteLine(e);
                _setupClient.Abort();
                _playClient.Abort();
            }
            catch (Exception e)
            {
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine(e);
            }
        }

        /// <summary>
        /// Process command and manage menu state
        /// </summary>
        /// <param name="Command">command string</param>
        public void ProcessCommand(string Command)
        {
            switch (_menuState)
            {
                case (int)MenuState.MAIN:
                    switch (Command)
                    {
                        case "1":
                            _setupClient.CreateNewEvent();
                            Console.WriteLine();
                            Console.Write("Add start/end dates <yyyy-mm-dd HH:MM>: ");
                            _menuState = (int)MenuState.ADD_DATES;
                            break;
                        case "2":
                            Console.WriteLine();
                            Console.Write("Enter event ID: ");
                            _menuState = (int)MenuState.JOIN_EVENT;
                            break;
                        default:
                            break;
                    }
                    break;

                case (int)MenuState.ADD_DATES:
                    string[] dates = Command.Split('/');
                    DateTime start = DateTime.Parse(dates[0]);
                    DateTime end = DateTime.Parse(dates[1]);
                    _setupClient.AddDates(start, end);
                    Console.WriteLine();
                    Console.Write("Add Speaker: ");
                    _menuState = (int)MenuState.ADD_SPEAKER;
                    break;

                case (int)MenuState.ADD_SPEAKER:
                    _setupClient.AddSpeaker(Command);
                    ShowCategories(_setupClient);
                    _menuState = (int)MenuState.SELECT_CATEGORY;
                    break;

                case (int)MenuState.SELECT_CATEGORY:
                    switch (Command)
                    {
                        case "0":
                            break;

                        default:
                            _setupClient.SelectBuzzwordCategory(_categories[int.Parse(Command) - 1].GetId.ToString());
                            break;
                    }

                    Console.WriteLine();
                    Console.WriteLine("terminate by pressing ENTER twice");
                    Console.Write("add participant <email>: ");
                    _menuState = (int)MenuState.ADD_PARTICIPANT;
                    break;

                case (int)MenuState.ADD_PARTICIPANT:
                    switch (Command)
                    {
                        case "":
                            _setupClient.SettleEvent();
                            Console.WriteLine();
                            Console.WriteLine("event saved!");
                            ShowMenu();
                            _menuState = (int)MenuState.MAIN;
                            break;

                        default:
                            _setupClient.AddParticipant(Command);
                            Console.WriteLine();
                            Console.Write("add participant <email>: ");
                            break;
                    }
                    break;

                case (int)MenuState.JOIN_EVENT:
                    if (Command.Length >= 36)
                        _eventId = Command;
                    _event =_playClient.JoinBingoEvent(_eventId);
                    ShowEvent(_event);
                    _winner = _playClient.GetWinner(_eventId);
                    if (_winner != null)
                    {
                        ShowWinner(_winner);
                        ShowMenu();
                        _menuState = (int)MenuState.MAIN;
                    }
                    else
                    {
                        Console.WriteLine();
                        Console.Write("Play as: ");
                        _menuState = (int)MenuState.PLAY_AS;
                    }
                    break;

                case (int)MenuState.PLAY_AS:
                    _playerParticipant = _playClient.PlayAs(_eventId, Command);
                    ShowParticipant(_playerParticipant);
                    Console.WriteLine();
                    Console.Write("mark word <index_number>: ");
                    _menuState = (int)MenuState.MARK_WORD;
                    break;

                case (int)MenuState.MARK_WORD:
                    _playClient.MarkBuzzWord(_eventId, _playerParticipant.Email, int.Parse(Command));
                    _winner = _playClient.GetWinner(_eventId);
                    if (_winner != null)
                    {
                        ShowWinner(_winner);
                        ShowMenu();
                        _menuState = (int)MenuState.MAIN;
                    }
                    else
                    {
                        Console.WriteLine();
                        Console.Write("mark word <index_number>: ");
                    }
                    break;

                default:
                    break;
            }
        }

        /// <summary>
        /// Show the main menu.
        /// </summary>
        public void ShowMenu()
        {
            Console.WriteLine();
            Console.WriteLine("*Menu*");
            Console.WriteLine("1: Create new Bingo event");
            Console.WriteLine("2: Play Bingo");
            Console.WriteLine("ctrl-c: Exit programm");
        }

        /// <summary>
        /// Show categories on console.
        /// </summary>
        /// <param name="Client">Setup Bingo Event Client</param>
        public void ShowCategories(SetupBingoEventClient Client)
        {
            int number = 0;
            Console.WriteLine();
            Console.WriteLine("Select a Category:");
            Console.WriteLine(number++ + ": none");
            if(_categories == null)
                _categories = Client.GetBuzzwordCategoryList();
            foreach (BuzzwordCategoryDto c in _categories)
                Console.WriteLine(number++ + ": " + c.Category);
        }

        /// <summary>
        /// Show bingo event detailes on console.
        /// </summary>
        /// <param name="Event">bingo event DTO</param>
        public void ShowEvent(BingoEventDto Event)
        {
            Console.WriteLine();
            Console.WriteLine("Dates: " + Event.StartDate.ToShortDateString() + " - " + Event.EndDate.ToShortDateString());
            Console.WriteLine("Speaker: " + Event.Speaker);
        }

        /// <summary>
        /// Show participant detailes on console.
        /// </summary>
        /// <param name="Participant">Participant DTO</param>
        public void ShowParticipant(ParticipantDto Participant)
        {
            Console.WriteLine();
            Console.WriteLine("email: " + Participant.Email);
            foreach (BuzzwordDto buzz in Participant.MyBingoCard.BuzzWords)
                Console.WriteLine(buzz.FuzzyWord + ": " + (buzz.IsMarked == true ? "marked" : "unmarked"));
        }

        /// <summary>
        /// Show winner message on console.
        /// </summary>
        /// <param name="Winner">Participant DTO</param>
        public void ShowWinner(ParticipantDto Winner)
        {
            Console.WriteLine();
            Console.WriteLine("aaaand the winner is: " + Winner.Email + " CONGRATULATIONS!!!");
        }

        #endregion
    }
}
